<?php
###########################################################################
#  Copyright (C) 2006-2007 Glyphix, Inc. <briz@glyphix.com>               #
#                                                                         #
#  Permission is hereby granted, free of charge, to any person obtaining  #
#  a copy of this software and associated documentation files (the        #
#  "Software"), to deal in the Software without restriction, including    #
#  without limitation the rights to use, copy, modify, merge, publish,    #
#  distribute, sublicense, and/or sell copies of the Software, and to     #
#  permit persons to whom the Software is furnished to do so, subject to  #
#  the following conditions:                                              #
#                                                                         #
#  The above copyright notice and this permission notice shall be         #
#  included in all copies or substantial portions of the Software.        #
#                                                                         #
#  Except as contained in this notice, the name(s) of the above           #
#  copyright holders shall not be used in advertising or otherwise to     #
#  promote the sale, use or other dealings in this Software without       #
#  prior written authorization.                                           #
#                                                                         #
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        #
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     #
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. #
#  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR      #
#  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  #
#  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  #
#  OTHER DEALINGS IN THE SOFTWARE.                                        #
###########################################################################

/**
 * GXPage_Modules
 *
 * Loads and caches specific modules under the name defined in System.xml.
 * @author		Brad Brizendine <briz@glyphix.com>
 * @link		http://www.glyphix.com/
 * @license		http://opensource.org/licenses/bsd-license.php BSD License
 * @version		1.0
 * @package		GXPage
 * @subpackage	Engine
 * @copyright	Copyright 2006 - 2007, Glyphix, Inc.
 * @uses		GXPage_SubClass
 */

class GXPage_Modules extends GXPage_SubClass {

	// cache module instances
	private $cache;

	/**
	 * getInstance
	 *
     * Returns the single unique instance of this class.
	 * @return object unique instance of this object
     */
	public static function getInstance(){
		return SingletonPattern::getSingleton( __CLASS__ );
	}

	// run all modules marked to @RunOnLoad
	public function __construct(){
		// only process RunOnLoad="1"
		$xpath = '/System/GXPage/Modules/*[ @RunOnLoad = "1" ]';
		if( !($list = GXPage::get('SystemConfig')->getConfig()->exec->xpath($xpath)) ){
			trigger_error( 'No active modules found in SystemConfig using ' .$xpath, E_USER_WARNING );
			return false;
		}

		// instantiate and cache each one
		foreach( $list as $config ){
			$name = $config->nodeName;
			$this->load($name,$config);
		}
		return $this;
	}

	/**
	 * load
	 *
	 * Load and configure a named module.
	 * @param string $name the name of the module
	 * @param object $config (optional) the config from System.xml
	 * @return object
	 */
	public function load( $name = null, $config = null ){
		if( !$name ){
			trigger_error( 'Missing module name', E_USER_ERROR );
			return false;
		}

		// if it's cached already, return it
		if( isset($this->cache[ $name ]) ){
			return $this->cache[ $name ];
		}

		// if we don't have a config, look for the config
		// otherwise, we're being called from this::__construct
		if( !$config ){
			$config = GXPage::get('SystemConfig')->getConfig()->exec->xpath( '/System/GXPage/Modules/' .$name, 0 );
			if( !$config ){
				trigger_error( 'No module definition by that name (' .$name .')', E_USER_ERROR );
				return false;
			}
		}

		// get the actual class name to instantiate
		$objName = $config->node->getAttribute('Implementation');
		if( !$objName ){
			$objName = $name;
		}

		// clone the config so we don't change the central systemconfig doc engine
		$conf = clone $config;

		// load the module:
			// second parameter is the alias to cache under in GXObject
			// third is the data to pass to the constructor
			// fourth is force instantiation if not found
		if( !($module = GXObject::get($objName,$name,$conf,true)) ){
			trigger_error( 'Unable to load module ' .$name .' implemented by ' .$objName .'; continuing with the next module', E_USER_ERROR );
			return false;
		}

		// cache
		$this->cache[ $name ] = $module;

		// execute <Init>
		if( $init = strval($config->Init) ){
			if( method_exists($module,$init) ){
				if( !($result = GXObject::run($module,$init)) ){
					trigger_error( 'Unable to execute Init method for module ' .$name, E_USER_WARNING );
					return false;
				}
			}
		}

		// log succesful module load
		trigger_error( 'Successfully loaded module ' .$name .' implemented by ' .$objName, E_USER_WARNING );

		// return the new module
		return $this->cache[ $name ];
	}

	/*
	 * __call
	 *
	 * Attempts to locate or instantiate the object named @method with @args.
	 */
	public function __call( $method = null, $args = null ){
		if( isset($this->cache[$method]) ){
			return $this->cache[$method];
		}
		trigger_error( 'Unable to locate a Module by that name (' .$method .')', E_USER_ERROR );
		return false;
	}

	/*
	 * __get
	 *
	 * Calls __call.
	 * Only works when not in static mode.
	 */
	public function __get( $name = null ){
		return $this->$name();
	}

}

?>